#include "mainform.h"

MainForm::MainForm()
{
	setupUi(this);

	m_SettingsDialog = new SettingsDialog(this);
	updateInterface();
	BothFrame->hide();

	connect(SwitchViewBtn, SIGNAL(clicked()), this, SLOT(switchView()));
	connect(SettingsBtn,   SIGNAL(clicked()), this, SLOT(execSettingsDialog()));

	m_Client_Socket = 0;
	m_Server_Socket = 0;
	m_Server_Peer   = 0;
	m_ActiveCodec = 0;
	m_CodecsList.clear();

	connect(ServerConnectBtn, SIGNAL(clicked()), this, SLOT(connectToServer()));
	connect(ClientConnectBtn, SIGNAL(clicked()), this, SLOT(listenForClient()));

	ClientAddrEdit->setText("0.0.0.0:20000");
	ClientConnectBtn->setText(tr("Listen"));
	ClientGroupBox->setTitle(tr("Client"));

	ServerAddrEdit->setText("127.0.0.1:10000");
	ServerConnectBtn->setText(tr("Connect"));
	ServerGroupBox->setTitle(tr("Server"));

	connect(ClientLogClearBtn, SIGNAL(clicked()), ClientLogWindow, SLOT(clear()));
	connect(ServerLogClearBtn, SIGNAL(clicked()), ServerLogWindow, SLOT(clear()));
	connect(BothLogClearBtn,   SIGNAL(clicked()), BothLogWindow,   SLOT(clear()));

//	ClientSendWindow->clear();
//	ServerSendWindow->clear();
	ClientLogWindow->clear();
	ServerLogWindow->clear();
	BothLogWindow->clear();
	DebugLogWindow->clear();

	QMenu *AboutMenu = new QMenu(this);
	AboutMenu->addAction(tr("About")+QString(" Developer's Proxy..."), this, SLOT(menu_about()));
	AboutMenu->addAction(tr("About")+QString(" Trolltech's Qt..."),    qApp, SLOT(aboutQt()));
	AboutBtn->setMenu(AboutMenu);

	//logWindow->setStyleSheet("QTextEdit { background: black }");
	//clientSendWindow->setStyleSheet("QTextEdit { background: white }");
	//ServerSendWindow->setStyleSheet("QTextEdit { background: white }");

	//logWindow->setHtml("<font color=white>");
}

void MainForm::loadCodecs()
{
	m_CodecsMenu = new QMenu(this);

	QDir CodecsDir = QDir(qApp->applicationDirPath() + "/codecs");

	foreach (QString FileName, CodecsDir.entryList(QDir::Files))
	{
		qDebug( "loadCodecs(): %s", qPrintable(FileName) );
		QPluginLoader Loader(CodecsDir.absoluteFilePath(FileName));
		QObject *QtPlugin = Loader.instance();

		if (QtPlugin)
		{
			qDebug( "->%s is Qt plugin", qPrintable(FileName) );
			CodecInterface *Codec = qobject_cast<CodecInterface*>(QtPlugin);
			if (Codec)
			{
				m_CodecsList.append(Codec);
				qDebug( "--->%s is DevProxy codec: %s", qPrintable(FileName),
						qPrintable(Codec->codecName()) );
			}
			else
			{
				qWarning( "--->%s is trash - unloaded", qPrintable(FileName) );
				delete QtPlugin;
				Loader.unload();
			}
		}

	}

	qDebug("------------------");
	QActionGroup *Group = new QActionGroup(this);
	Group->setExclusive(true);
	connect(Group, SIGNAL(triggered(QAction*)), this, SLOT(updateActiveCodec(QAction*)));

	for(int i = 0; i < m_CodecsList.count(); ++i)
	{
		CodecInterface *Codec = m_CodecsList.at(i);
		QString CodecName = Codec->codecName();
		QString CodecDesc = Codec->codecDesc();
		qDebug("name: %s desc: %s", qPrintable(CodecName), qPrintable(CodecDesc) );
		QAction *Act = Group->addAction(CodecName);
		Act->setToolTip(CodecDesc);
		Act->setCheckable(true);
		if (CodecName == "text")
		{
			Act->setChecked(true);
			updateActiveCodec(Act);
		}
	}

	m_CodecsMenu->addActions(Group->actions());
	m_CodecsMenu->addSeparator();

	m_CodecsMenu->addAction(tr("Configure selected codec"), this, SLOT(configureActiveCodec()));
	
	CodecsBtn->setMenu(m_CodecsMenu);
}

void MainForm::updateActiveCodec(QAction *Action)
{
	qDebug("updateActiveCodec()");

	for(int i = 0; i < m_CodecsList.count(); ++i)
	{
		if (m_CodecsList.at(i)->codecName() == Action->text())
			m_ActiveCodec = m_CodecsList.at(i);
	}

	if (m_ActiveCodec != 0)
		qDebug("->m_ActiveCodec is %s", qPrintable( m_ActiveCodec->codecName() ) );
}

void MainForm::configureActiveCodec()
{
	if (m_ActiveCodec != 0)
		m_ActiveCodec->showParamsDialog();
}

void MainForm::execSettingsDialog()
{
	int Res = m_SettingsDialog->exec();
	if (QDialog::Accepted == Res) updateInterface();
}

void MainForm::updateInterface()
{
	m_SettingsDialog->debugMode() ? DebugLogWindow->show() : DebugLogWindow->hide();

	QFont Font = m_SettingsDialog->font();
	QString Style = "QTextEdit { background: black; font-family: \"%1\"; }";
	Style = Style.arg(Font.family());
	ServerLogWindow->setStyleSheet(Style);
	ClientLogWindow->setStyleSheet(Style);
	BothLogWindow->setStyleSheet(Style);

	m_Autoconnect = m_SettingsDialog->autoconnect();
	m_Line = ( m_SettingsDialog->needLine() ) ? m_SettingsDialog->line() : QString();
}

void MainForm::menu_about()
{
	QString About = QString("Developer's Proxy ");
	About+= tr("is a cool program. :)");

	QString License = tr("Copyright (c) 2008 Alek Silverstone");
	License += "<br/>" + tr(
		"Permission is hereby granted, free of charge, to any person obtaining a copy "
		"of this software and associated documentation files (the \"Software\"), to deal "
		"in the Software without restriction, including without limitation the rights "
		"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell "
		"copies of the Software, and to permit persons to whom the Software is "
		"furnished to do so, subject to the following conditions:"
		);
	License += "<br/>" + tr(
		"The above copyright notice and this permission notice shall be included in "
		"all copies or substantial portions of the Software."
		);

	License += "<br/>" + tr(
		"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR "
		"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, "
		"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE "
		"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER "
		"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, "
		"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN "
		"THE SOFTWARE."
		);

	QString Text = "<html>" + About + "<br/>" + License + "</html>";
	QMessageBox::about(this, tr("About")+QString(" Developer's Proxy"), Text);
}

void MainForm::connectToServer()
{
	qDebug("connectToServer()");

	if (m_Client_Socket != 0)
	{
		qWarning("->m_Client_Socket != 0");
		return;
	}

	m_Client_Socket = new QTcpSocket(this);
	QStringList ap = ServerAddrEdit->text().split(":");
	m_Client_Socket->connectToHost(ap[0],ap[1].toInt());

	ServerConnectBtn->disconnect(SIGNAL(clicked()));
	connect(ServerConnectBtn,SIGNAL(clicked()),this,SLOT(disconnectFromServer()));
	ServerConnectBtn->setText(tr("Disconnect"));

	connect(m_Client_Socket, SIGNAL(disconnected()), this, SLOT(disconnectFromServer()));
	connect(m_Client_Socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this,
		SLOT(socketStateChanged(QAbstractSocket::SocketState)));
	connect(m_Client_Socket, SIGNAL(readyRead()), this, SLOT(readDataFromServer()));

	qDebug("connectToServer done");
}

void MainForm::disconnectFromServer()
{
	qDebug("disconnectFromServer()");

	if (m_Client_Socket == 0)
	{
		qWarning("->m_Client_Socket == 0");
		return;
	}

	m_Client_Socket->disconnect(SIGNAL(disconnected()));
	m_Client_Socket->close();
	m_Client_Socket->deleteLater();
	m_Client_Socket = 0;

	ServerConnectBtn->disconnect(SIGNAL(clicked()));
	connect(ServerConnectBtn,SIGNAL(clicked()),this,SLOT(connectToServer()));
	ServerConnectBtn->setText(tr("Connect"));

	qDebug("disconnectFromServer done");
}

void MainForm::socketStateChanged(QAbstractSocket::SocketState i)
{
	QString m;
	switch (i)
	{
		case 0:
			m="unconnected";
			break;
		case 1:
			m="host lookup";
			break;
		case 2:
			m="connecting...";
			break;
		case 3:
			m="connected";
			break;
		case 4:
			m="bound";
			break;
		case 6:
			m="closing...";
			break;
		default:
			m="internal value";
	}

	qDebug( "socketStateChanged: %d - %s", i, qPrintable(m) );
}


void MainForm::listenForClient()
{
	qDebug("listenForClient()");

	if (m_Server_Socket != 0)
	{
		qWarning("->m_Server_Socket != 0");
		return;
	}

	m_Server_Socket = new QTcpServer(this);
	QStringList ap = ClientAddrEdit->text().split(":");
	m_Server_Socket->listen(QHostAddress(ap[0]),ap[1].toInt());
	m_Server_Socket->setMaxPendingConnections(1);

	ClientConnectBtn->disconnect(SIGNAL(clicked()));
	connect(ClientConnectBtn,SIGNAL(clicked()),this,SLOT(deafForClient()));
	connect(m_Server_Socket,SIGNAL(newConnection()),this,SLOT(getPeer()));

	ClientConnectBtn->setText(tr("Deaf"));

	qDebug("listenForClient done");
}

void MainForm::deafForClient()
{
	qDebug("deafForClient()");

	if (m_Server_Socket == 0)
	{
		qWarning("->m_Server_Socket == 0");
		return;
	}

	m_Server_Socket->close();
	m_Server_Socket->deleteLater();
	m_Server_Socket = 0;

	ClientConnectBtn->disconnect(SIGNAL(clicked()));
	connect(ClientConnectBtn,SIGNAL(clicked()),this,SLOT(listenForClient()));
	ClientConnectBtn->setText(tr("Listen"));

	qDebug("deafForServer done");
}

void MainForm::getPeer()
{
	qDebug("getPeer()");

	if (m_Server_Peer != 0)
	{
		qWarning("->m_Server_Peer != 0");
		return;
	}

	m_Server_Peer = m_Server_Socket->nextPendingConnection();
	qDebug("  peer=%lu", (ulong)m_Server_Peer );

	connect(m_Server_Peer, SIGNAL(readyRead()), this, SLOT(readDataFromClient()));
	connect(m_Server_Peer, SIGNAL(disconnected()), this, SLOT(dropPeer()));
	connect(m_Server_Peer, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this,
		SLOT(socketStateChanged(QAbstractSocket::SocketState)));

	if (m_Client_Socket == 0)
	{
		qWarning("->m_Client_Socket == 0 !");
		if (m_Autoconnect)
		{
			qDebug("--->autoconnect");
			connectToServer();
		}
	}
	
	qDebug("getPeer done");
}

void MainForm::dropPeer()
{
	qDebug("dropPeer()");
	qDebug("  peer=%lu", (ulong)m_Server_Peer );

	m_Server_Peer->close();
	m_Server_Peer->deleteLater();
	m_Server_Peer = 0;

	qDebug("dropPeer done");
}

void MainForm::readDataFromClient()
{
	qDebug("readDataFromClient()");

	qint64 bytes = m_Server_Peer->bytesAvailable();
	qDebug("  bytes: %lu", (long unsigned) bytes );
	if (! m_Line.isNull())
	{
		QString line = m_Line.replace("%size",QString::number(bytes));
		line = "<font color=\"white\">" + line + "</font>";
		BothLogWindow->append(line);
		ClientLogWindow->append(line);
	}
	
	QByteArray ba=m_Server_Peer->readAll();
	
	if (m_Client_Socket == 0)
	{
		qWarning("->m_Client_Socket == 0 !");
		if (m_Autoconnect)
		{
			qDebug("--->autoconnect");
			connectToServer();
		}
	}
	
	if (m_Client_Socket !=0)
		m_Client_Socket->write(ba);

	QString Readed;
	m_ActiveCodec ? Readed = m_ActiveCodec->decode(ba,true) : Readed = ba;
	BothLogWindow->append(Readed);
	ClientLogWindow->append(Readed);

	qDebug("readDataFromClient done");
}

void MainForm::readDataFromServer()
{
	qDebug("readDataFromServer()");

	qint64 bytes = m_Client_Socket->bytesAvailable();
	qDebug("  bytes: %lu", (long unsigned) bytes);
	if (! m_Line.isNull())
	{
		QString line = m_Line.replace("%size",QString::number(bytes));
		line = "<font color=\"white\">" + line + "</font>";
		BothLogWindow->append(line);
		ServerLogWindow->append(line);
	}

	QByteArray ba=m_Client_Socket->readAll();
	if (m_Server_Peer != 0)
		m_Server_Peer->write(ba);
	else
		qWarning("->m_Server_Peer == 0 !");

	QString Readed;
	m_ActiveCodec ? Readed = m_ActiveCodec->decode(ba,false) : Readed = ba;
	BothLogWindow->append(Readed);
	ServerLogWindow->append(Readed);

	qDebug("readDataFromServer done");
}

void MainForm::switchView()
{
	if (BothFrame->isVisible())
	{
		BothFrame->hide();
		ClientFrame->show();
		ServerFrame->show();
	}
	else
	{
		ClientFrame->hide();
		ServerFrame->hide();
		BothFrame->show();
	}
}

///////////////////////////////////////////////////////////////////////////

void MainForm::debugMessage(QtMsgType type, const char *msg)
{
	switch (type)
	{
		case QtDebugMsg:
			DebugLogWindow->append( QString("Debug: ") + QString(msg) );
			break;
		case QtWarningMsg:
			DebugLogWindow->append( QString("Warning: ") + QString(msg) );
			break;
		case QtCriticalMsg:
			DebugLogWindow->append( QString("Critical: ") + QString(msg) );
			fprintf(stderr, "Critical: %s\n", msg);
			break;
		case QtFatalMsg:
			DebugLogWindow->append( QString("Fatal: ") + QString(msg) );
			fprintf(stderr, "Fatal: %s\n", msg);
			close();
	}
}

// kate: space-indent off; tab-indents on; indent-width 4; indent-mode cstyle;
